package qq2564874169.tuaotuao.fx;


import qq2564874169.tuaotuao.fx.utils.ConvertUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class FxDate extends Date {
    public final static int SECONDS = 1000;
    public final static int MINUTES = SECONDS * 60;
    public final static int HOURS = MINUTES * 60;
    public final static int DAY = HOURS * 24;
    public final static FxDate MAX = FxDate.tryParse("9999-12-31 23:59:59");
    public final static FxDate MIN = FxDate.tryParse("0001-1-1");
    private final int tzOffset = Calendar.getInstance().getTimeZone().getRawOffset();
    private Calendar calendar = Calendar.getInstance();

    public static long toMillisBySeconds(int num) {
        return (long) num * SECONDS;
    }

    public static long toMillisByMinutes(int num) {
        return (long) num * MINUTES;
    }

    public static long toMillisByHours(int num) {
        return (long) num * HOURS;
    }

    public static long toMillisByDay(int num) {
        return (long) num * DAY;
    }

    public static FxDate parseByExpr(String date, String expr) {
        try {
            return new FxDate(new SimpleDateFormat(expr).parse(date));
        } catch (ParseException e) {
            return null;
        }
    }

    public static FxDate parseByYm(Integer yyyyMM) {
        return parseByYmd(yyyyMM * 100 + 1);
    }

    public static FxDate parseByYmd(Integer ymd) {
        return tryParse(ymd.toString(), "yyyyMMdd");
    }

    public static FxDate tryParse(String date) {
        Date value = ConvertUtil.change(date, Date.class);
        return value == null ? null : new FxDate(value);
    }

    public static FxDate tryParse(String date, String expr) {
        return FxDate.parseByExpr(date, expr);
    }

    public static FxDate weekOfYear(int year, int week) {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setMinimalDaysInFirstWeek(7);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.WEEK_OF_YEAR, week);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return new FxDate(calendar.getTime()).toDate();
    }

    public static Long currentTime() {
        return new FxDate().yyyyMMddHHmmss();
    }

    public FxDate() {
        this(System.currentTimeMillis());
    }

    public FxDate(Date date) {
        this(date.getTime());
    }

    public FxDate(long time) {
        if (time > 9999999999999L && time < 99999999999999L) {
            int year = (int) (time / 10000000000L);
            int month = (int) (time % 10000000000L / 100000000L);
            int day = (int) (time % 100000000L / 1000000L);
            int hh = (int) (time % 1000000L / 10000L);
            int mm = (int) (time % 10000L / 100L);
            int ss = (int) (time % 100L);
            Calendar calendar = getCalendar();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month - 1);
            calendar.set(Calendar.DAY_OF_MONTH, day);
            calendar.set(Calendar.HOUR_OF_DAY, hh);
            calendar.set(Calendar.MINUTE, mm);
            calendar.set(Calendar.SECOND, ss);
            calendar.set(Calendar.MILLISECOND, 0);
            this.setTime(calendar.getTime().getTime());
        } else {
            this.setTime(time);
        }
    }

    public FxDate toDate() {
        return new FxDate(getTime() - ((getTime() + tzOffset) % DAY));
    }

    public String format(String expr) {
        SimpleDateFormat fmt = new SimpleDateFormat(expr);
        return fmt.format(this);
    }

    public String format() {
        return format("yyyy-MM-dd HH:mm:ss");
    }

    public Calendar getCalendar() {
        calendar.setTime(this);
        return calendar;
    }

    public FxDate addYear(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.YEAR, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addMonth(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.MONTH, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addDay(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.DAY_OF_YEAR, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addHour(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.HOUR_OF_DAY, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addMinute(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.MINUTE, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addSecond(int value) {
        Calendar calendar = getCalendar();
        calendar.add(Calendar.SECOND, value);
        return new FxDate(calendar.getTime());
    }

    public FxDate addMillis(long value) {
        return new FxDate(getTime() + value);
    }

    public int day() {
        return (int) ((getTime() + tzOffset) / DAY) + 1;
    }

    public int dayOfMonth() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public int dayOfWeek() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.DAY_OF_WEEK);
    }

    public int dayOfYear() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public Integer yyyyMM() {
        return year() * 100 + month();
    }

    public Integer yyyyMMdd() {
        return year() * 10000 + month() * 100 + dayOfMonth();
    }

    public Integer hhmmss() {
        return hour() * 10000 + minute() * 100 + second();
    }

    public Long yyyyMMddHHmmss() {
        return yyyyMMdd() * 1000000L + hhmmss();
    }

    public int year() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.YEAR);
    }

    public int month() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.MONTH) + 1;
    }

    public int totalMonth() {
        int y = (year() - 1970) * 12;
        return y + month();
    }

    public int hour() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    public int minute() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.MINUTE);
    }

    public int second() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.SECOND);
    }

    public int millisecond() {
        Calendar calendar = getCalendar();
        return calendar.get(Calendar.MILLISECOND);
    }

    public FxDate firstDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year());
        calendar.set(Calendar.MONTH, month() - 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return new FxDate(calendar.getTime()).toDate();
    }

    public FxDate firstDayOfWeek() {
        Calendar calendar = getCalendar();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return new FxDate(calendar.getTime()).toDate();
    }

    @Override
    public String toString() {
        return format();
    }
}
